package com.hmall.search.service.imp;


import com.alibaba.fastjson.JSON;
import com.hmall.common.client.ItemClient;
import com.hmall.common.dto.Item;
import com.hmall.common.dto.PageDTO;
import com.hmall.search.pojo.ItemDoc;
import com.hmall.search.pojo.RequestParams;
import com.hmall.search.service.ISearchService;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;


@Service
public class SearchService implements ISearchService {

    @Autowired
    RestHighLevelClient client;
    @Autowired
    ItemClient itemClient;
    @Override
    public PageDTO<ItemDoc> pageSearch(RequestParams requestParams) throws IOException {
        //准备请求
        SearchRequest request = new SearchRequest("item");
        //准备SDL
        //条件搜索方法
        buildBasicQuery(requestParams,request);
        //分页
        Integer size = requestParams.getSize();
        Integer page = requestParams.getPage();
        request.source().from((page-1) * size).size(size);
        //排序
        String sortBy = requestParams.getSortBy();
        //销量降序
        if(sortBy.equals("sold")){
            request.source().sort(sortBy, SortOrder.DESC);
            //价格升序
        }else if (sortBy.equals("price")){
            request.source().sort(sortBy,SortOrder.ASC);
        }
        //高亮
        request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
        //发起请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //结果解析
        return getItemDocPageDTO(response);

    }



    private PageDTO<ItemDoc> getItemDocPageDTO(SearchResponse response) {
        SearchHits searchHits= response.getHits();
        //获取总条目数
        long totalhits = searchHits.getTotalHits().value;
        //获取数据内容
        SearchHit[] hits = searchHits.getHits();
        ArrayList<ItemDoc> items = new ArrayList<>(hits.length);
        for (SearchHit hit : hits) {
            //转化为字符串
            String json = hit.getSourceAsString();
            //JSON形式
            ItemDoc itemDoc = JSON.parseObject(json, ItemDoc.class);
            //获取高亮结果
            Map<String, HighlightField> map = hit.getHighlightFields();
            if(map!=null&&map.size()>0){
                //根据字段获取高亮结果
                HighlightField field = map.get("name");
                //获取高亮值
                String value = field.getFragments()[0].string();
                //覆盖非高亮结果
                itemDoc.setBrand(value);
            }
            //将值传入集合中、
            items.add(itemDoc);
        }
        return new PageDTO<>(totalhits,items);
    }

    /**
     * 条件过滤查询
     * @param requestParams
     * @param request
     */
    private void buildBasicQuery(RequestParams requestParams,SearchRequest request){
        //准备boolean查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //关键字搜索
        String key = requestParams.getKey();
        //判断有无条件查询，没有则是全局查询
        if(key==null || key.equals("")){
            boolQuery.must(QueryBuilders.matchAllQuery());
        }else {
            //匹配查询
            boolQuery.must(QueryBuilders.matchQuery("all",key));
        }
        //分类、品牌、价格过滤
        if(requestParams.getBrand()!=null&&!requestParams.getBrand().equals("")){
            boolQuery.filter(QueryBuilders.termQuery("brand",requestParams.getBrand()));
        }
        if(requestParams.getCategory()!=null&&!requestParams.getCategory().equals("")){
            boolQuery.filter(QueryBuilders.termQuery("category",requestParams.getCategory()));
        }
        if(requestParams.getMinPrice()!=null&&requestParams.getMaxPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").
                    gte(requestParams.getMinPrice()*100).lte(requestParams.getMaxPrice()*100));
        }
        //排名算分控制
        FunctionScoreQueryBuilder functionScore = QueryBuilders.functionScoreQuery(boolQuery,
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                QueryBuilders.termQuery("isAD", true),
                                ScoreFunctionBuilders.weightFactorFunction(100)
                        )
                });
        //发送请求
        request.source().query(functionScore);

    }
    /**
     * 上架添加商品
     * @param id
     */
    @Override
    public void updateById(Long id) throws IOException {
        //查询商品
        Item item = itemClient.ItemById(id);
        //发送请求
        BulkRequest bulkRequest = new BulkRequest();
        //准备参数，添加参数
            ItemDoc itemDoc = new ItemDoc(item);
            bulkRequest.add(new IndexRequest("item").
                    //转为字符串形式
                    id(id.toString())
                    .source(JSON.toJSONString(itemDoc), XContentType.JSON));
        //响应结果
        client.bulk(bulkRequest, RequestOptions.DEFAULT);



    }

    /**
     * 下架删除商品
     * @param id
     */
    @Override
    public void downDeteleByTd(Long id) throws IOException {
        //发送请求
        DeleteRequest deleteRequest = new DeleteRequest("item",id.toString());
        //接受请求
        client.delete(deleteRequest,RequestOptions.DEFAULT);

    }
}
